package com.viking.framework.dao.impl;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.viking.framework.dao.HibernateDao;
import com.viking.framework.pages.PageCut;

public class HibernateEntityDao extends HibernateDaoSupport implements
		HibernateDao {
	/**
	 * 去除hql的orderby 子句，用于pagedQuery.
	 * 
	 * @see #pagedQuery(String, int, int, Object[])
	 */
	private static String removeOrders(String hql) {
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*",
				Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 去除hql的select 子句，未考虑union的情况,用于pagedQuery.
	 * 
	 * @see #pagedQuery(String, int, int, Object[])
	 */
	private static String removeSelect(String hql) {
		int beginPos = hql.toLowerCase().indexOf("from");
		return hql.substring(beginPos);
	}

	public List findByHql(String hql, Object values[]) {
		return getHibernateTemplate().find(hql, values);
	}

	public List getAll(Class clazz) {
		return getHibernateTemplate().loadAll(clazz);
	}

	public Object getObject(Class clazz, Serializable id) {
		Object o = getHibernateTemplate().get(clazz, id);
		return o;
	}

	public void removeObject(Class clazz, Serializable id) {
		removeObject(getObject(clazz, id));
	}

	/**
	 * 删除对象
	 */
	public void removeObject(Object obj) {
		if (obj != null) {
			getHibernateTemplate().delete(obj);
		}
	}

	/**
	 * 保存对象
	 */
	public void saveObject(Object o) {
		getHibernateTemplate().save(o);
	}

	/**
	 * Update Object
	 */
	public void updateObject(Object o) {
		getHibernateTemplate().update(o);
	}

	/**
	 * cut page results
	 */
	public PageCut pageQueryByHql(String hql, Object[] values, int start,
			int pageSize) {
		long total = this.getTotalSize(hql, values);
		List list = this.getPageList(hql, values, start, pageSize);
		if (pageSize == 0)
			pageSize = 10;
		int no = start / pageSize + 1;
		PageCut page = new PageCut();
		page.setPageNo(no);
		page.setPageSize(pageSize);
		page.setStart(start);
		page.setTotalSize(total);
		page.setResults(list);
		return page;
	}

	/**
	 * 
	 * <p>
	 * Description: get records by page cutting
	 * </p>
	 * 
	 * @param hql
	 * @param values
	 * @param start
	 * @param limit
	 * @return
	 * @author Yzc
	 */
	private List getPageListSql(String sql, Object[] values, int start,
			int limit) {
		Query querySession = this.createSQLQuery(sql, values);
		if (querySession == null)
			return null;
		querySession.setFirstResult(start);
		querySession.setMaxResults(limit);
		return querySession.list();
	}

	/**
	 * 
	 * <p>
	 * Description: get records by page cutting
	 * </p>
	 * 
	 * @param hql
	 * @param values
	 * @param start
	 * @param limit
	 * @return
	 * @author Yzc
	 */
	private List getPageList(String hql, Object[] values, int start, int limit) {
		Query querySession = this.createHQLQuery(hql, values);
		if (querySession == null)
			return null;
		querySession.setFirstResult(start);
		querySession.setMaxResults(limit);
		return querySession.list();
	}

	/**
	 * 
	 * <p>
	 * Description: create HQL query with parameters
	 * </p>
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @author Yzc
	 */
	protected Query createHQLQuery(String hql, Object[] values) {
		Query query = getSession().createQuery(hql);
		if (values != null && values.length != 0) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}

	/**
	 * 
	 * <p>
	 * Description: create SQL query with parameters
	 * </p>
	 * 
	 * @param sql
	 * @param values
	 * @return
	 * @author Yzc
	 */
	protected SQLQuery createSQLQuery(String sql, Object[] values) {
		SQLQuery query = getSession().createSQLQuery(sql);
		if (values != null && values.length != 0) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		// query.addScalar("content", Hibernate.STRING);
		return query;
	}

	/**
	 * 
	 * 获取 records size
	 * 
	 */
	private long getTotalSizeSql(String sql, Object[] values) {
		String countQueryString = "select count(*) "
				+ removeSelect(removeOrders(sql));
		Query query = this.createSQLQuery(countQueryString, values);
		Object obj = query.list().get(0);
		BigInteger bigInt = (BigInteger) obj;
		if (bigInt == null)
			return 0;
		else
			return bigInt.longValue();
	}

	/**
	 * 
	 * 获取 records size
	 * 
	 */
	private long getTotalSize(String hql, Object[] values) {
		String countQueryString = "select count(*) "
				+ removeSelect(removeOrders(hql));
		Query query = this.createHQLQuery(countQueryString, values);
		Long tl = (Long) query.iterate().next();
		if (tl == null)
			return 0;
		else
			return tl.longValue();
	}

	public List executeSqlQuery(String sql, Object[] values) {
		return this.createSQLQuery(sql, values).list();
	}

	public int executeSqlUpdate(String sql, Object[] values) {
		return this.createSQLQuery(sql, values).executeUpdate();
	}

	public Session getHibernateSession() {
		return this.getSession();
	}

	public int bulkUpdate(String hql, Object[] values) {
		return getHibernateTemplate().bulkUpdate(hql, values);
	}

	public PageCut pageQueryBySql(String sql, Object[] values, int start,
			int pageSize) {
		long total = this.getTotalSizeSql(sql, values);
		List list = this.getPageListSql(sql, values, start, pageSize);
		if (pageSize == 0)
			pageSize = 10;
		int no = start / pageSize + 1;
		PageCut page = new PageCut();
		page.setPageNo(no);
		page.setPageSize(pageSize);
		page.setStart(start);
		page.setTotalSize(total);
		page.setResults(list);

		return page;
	}

	public void saveOrUpdate(Object o) {
		getHibernateTemplate().saveOrUpdate(o);
	}
}
